package br.ufc.apsoo.models;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.validation.constraints.NotNull;

import br.ufc.apsoo.utils.DateUtils;

@Entity
@Table(name = "reserva")
@SequenceGenerator(name = "seq_reserva", sequenceName = "seq_reserva")
public class Reserva {

	@Id
	@Column(name = "id_reserva")
	@GeneratedValue(generator = "seq_reserva", strategy = GenerationType.AUTO)
	private Long id;

	@NotNull(message = "A data de entrada é obrigatória!")
	@Column(name = "data_entrada")
	private Date dataEntrada;

	@NotNull(message = "A data de saída é obrigatória!")
	@Column(name = "data_saida")
	private Date dataSaida;

	@NotNull(message = "A situação da reserva deve ser setada!")
	@Column(name = "situacao")
	private Situacao situacao;

	@ManyToOne(fetch = FetchType.EAGER)
	private Hospede hospede;

	@ManyToOne(fetch = FetchType.EAGER)
	private Apartamento apartamento;

	@OneToMany(mappedBy = "id", cascade = CascadeType.ALL)
	@JoinColumn(name = "id_reserva")
	private List<Despesa> despesas;

	@Transient
	private BigDecimal valorTotalDeDiarias;

	@Transient
	private BigDecimal valorTotalDeDespesas;

	public Reserva() {
		super();
		hospede = new Hospede();
		apartamento = new Apartamento();
		despesas = new ArrayList<Despesa>();
	}

	public void checkin() {
		this.situacao = Situacao.OCUPADO;
	}

	public void checkout() {
		this.situacao = Situacao.LIVRE;
	}

	public Apartamento getApartamento() {
		return apartamento;
	}

	public Date getDataEntrada() {
		return dataEntrada;
	}

	public Date getDataSaida() {
		return dataSaida;
	}

	public List<Despesa> getDespesas() {
		return despesas;
	}

	public Hospede getHospede() {
		return hospede;
	}

	public Long getId() {
		return id;
	}

	public Situacao getSituacao() {
		return situacao;
	}

	public BigDecimal getValorTotalDeDespesas() {

		valorTotalDeDespesas = BigDecimal.ZERO;

		for (Despesa despesa : despesas) {
			if (!despesa.foiEstornada()) {
				valorTotalDeDespesas = valorTotalDeDespesas.add(despesa
						.getServico().getValor()
						.multiply(new BigDecimal(despesa.getQuantidade())));
			}
		}

		return valorTotalDeDespesas;
	}

	public BigDecimal getValorTotalDeDiarias() {

		if (dataEntrada == null || dataSaida == null
				|| apartamento.getTipoApartamento() == null) {
			return BigDecimal.ZERO;
		}
		
		Integer numeroDeDiarias = null;
		
		if (dataSaida.after(new Date())) {
			numeroDeDiarias = DateUtils.numberOfDaysBetween(new Date(),
					dataEntrada);
		} else {
			numeroDeDiarias = DateUtils.numberOfDaysBetween(dataSaida,
					dataEntrada);
		}

		if (numeroDeDiarias < 1) {
			numeroDeDiarias = 1;
		}
		
		return apartamento.getTipoApartamento().getValor()
				.multiply(new BigDecimal(numeroDeDiarias));
	}

	public void reservar() {
		this.situacao = Situacao.RESERVADO;
	}

	public void setApartamento(Apartamento apartamento) {
		this.apartamento = apartamento;
	}

	public void setDataEntrada(Date dataEntrada) {
		this.dataEntrada = dataEntrada;
	}

	public void setDataSaida(Date dataSaida) {
		this.dataSaida = dataSaida;
	}

	public void setDespesas(List<Despesa> despesas) {
		this.despesas = despesas;
	}

	public void setHospede(Hospede hospede) {
		this.hospede = hospede;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public void setSituacao(Situacao situacao) {
		this.situacao = situacao;
	}

	public void setValorTotalDeDespesas(BigDecimal valorTotalDeDespesas) {
		this.valorTotalDeDespesas = valorTotalDeDespesas;
	}

	public void setValorTotalDeDiarias(BigDecimal valorTotalDeDiarias) {
		this.valorTotalDeDiarias = valorTotalDeDiarias;
	}

}
